package com.ljj.dolls;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DollsMap {

    private Map<Class, Dolls> map = new ConcurrentHashMap<>();

    /**
     * put  KV
     * @param key
     * @param value
     */
    public void put(Object key, Object value) {
        Dolls d = null;
        if (isBaseType(key)) {
            d = map.putIfAbsent(value.getClass(), new Dolls());
            d = map.get(value.getClass());
        } else {
            d = map.putIfAbsent(key.getClass(), new Dolls());
            d = map.get(key.getClass());
        }

        Object[] innerKey = getInnerKey(key);
        int len = innerKey.length;
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {
                d.put(innerKey[i], value);
            } else {
                d.putDolls(innerKey[i]);
                d = d.getDolls(innerKey[i]);
                if(d==null){
                    break;
                }
            }
        }
    }

    /**
     * 直接put KV，以args创建链表key
     * @param key
     * @param value
     * @param args
     */
    public void put(Object key, Object value,Object... args) {
        Dolls d = null;
        if (isBaseType(key)) {
            d = map.putIfAbsent(value.getClass(), new Dolls());
            d = map.get(value.getClass());
        } else {
            d = map.putIfAbsent(key.getClass(), new Dolls());
            d = map.get(key.getClass());
        }

        Object[] innerKey = args;//getInnerKey(key);
        int len = innerKey.length;
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {
                d.put(innerKey[i], value);
            } else {
                d.putDolls(innerKey[i]);
                d = d.getDolls(innerKey[i]);
                if(d==null){
                    break;
                }
            }
        }
    }

    /**
     * 取值，如果valueClass非空，就查valueClass类型的值
     * @param key
     * @param valueClass
     * @return
     */
    public Object get(Object key, Class valueClass) {
        if (valueClass != null) {
            return map.get(valueClass).get(key);
        } else {
            Object res = null;
            Dolls d = map.get(key.getClass());
            Object[] innerKey ;
            if(key instanceof Key){
                innerKey = ((Key) key).keys();
            }else{
                innerKey = getInnerKey(key);
            }

            int len = innerKey.length;
            for (int i = 0; i < len; i++) {
                if (i == len - 1) {
                    res = d.get(innerKey[i]);
                } else {
                    d = d.getDolls(innerKey[i]);
                    if(d==null){
                        return null;
                    }
                }
            }
            return res;
        }
    }

    /**
     * 取值，如果valueClass非空，就取valueClass类型的值
     * @param key
     * @param valueClass
     * @param args
     * @return
     */
    public Object get(Object key, Class valueClass,Object... args) {
        if (valueClass != null) {
            return map.get(valueClass).get(key);
        } else {
            Object res = null;
            Dolls d = map.get(key.getClass());
            Object[] innerKey = args;//getInnerKey(key);
            int len = innerKey.length;
            for (int i = 0; i < len; i++) {
                if (i == len - 1) {
                    res = d.get(innerKey[i]);
                } else {
                    d = d.getDolls(innerKey[i]);
                    if(d==null){
                        return null;
                    }
                }
            }
            return res;
        }
    }

    /**
     * 通过反射自动生成链表key
     * @param key
     * @return
     */
    public Object[] getInnerKey(Object key) {
        if (isBaseType(key)) {
            return new Object[]{key};
        }
        Field[] fs = key.getClass().getDeclaredFields();
        Object[] res = new Object[fs.length];
        for (int i = 0; i < fs.length; i++) {
            boolean access = fs[i].isAccessible();
            fs[i].setAccessible(true);
            try {
                res[i] = fs[i].get(key);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            fs[i].setAccessible(access);
        }

        return res;
    }

    public static boolean isBaseType(Object object) {
        if (object instanceof Enum ||
                object instanceof Integer ||
                object instanceof Byte ||
                object instanceof Long ||
                object instanceof String ||
                object instanceof Double ||
                object instanceof Float ||
                object instanceof Character ||
                object instanceof Short ||
                object instanceof Boolean) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        DollsMap d=new DollsMap();
        long t1=System.currentTimeMillis();
        for(int i=0;i<20000000;i++){
            DollsMap.isBaseType(i/2==0);
            //d.getInnerKey(new Main.Key1(i,i,i,i,i));
        }
        long t2=System.currentTimeMillis();
        System.out.println(t2-t1);
    }
}
